﻿using System.Collections.Generic;
using NHibernate.Criterion;

namespace Apollo.Core
{
    public class FilterGroup
    {
        public FilterGroup() {
            this.Groups = new List<FilterGroup>();
            this.Rules = new List<FilterRule>();
        }

        public GroupOperator Operator { get; set; }

        public List<FilterRule> Rules { get; set; }

        public List<FilterGroup> Groups { get; set; }

        public List<Projection> Projections {
            get {
                List<Projection> projections = new List<Projection>();

                foreach (FilterRule rule in this.Rules)
                    if(rule.Projection.IsValid)
                        projections.Add(rule.Projection);

                foreach (FilterGroup group in this.Groups)
                    if(group != null && group.Projections != null)
                        projections.AddRange(group.Projections);

                return projections;
            }
        }

        public bool IsEmpty { get {
            if (this.Rules.Count > 0)
                return false;

            foreach (FilterGroup grup in this.Groups)
                if (!grup.IsEmpty)
                    return false;

            return true;
        } }

        public ICriterion ToCriterion() {
            ICriterion criterion = null;

            foreach (FilterGroup group in this.Groups) 
            {
                if (group == null) continue;

                ICriterion innerCriterion = group.ToCriterion();

                if(innerCriterion == null)
                    continue;

                if (criterion == null)
                    criterion = innerCriterion;
                else if (this.Operator == GroupOperator.And)
                    criterion = new NHibernate.Criterion.AndExpression(criterion, innerCriterion);
                else
                    criterion = new NHibernate.Criterion.OrExpression(criterion, innerCriterion);
            }

            foreach (FilterRule rule in this.Rules)
            {
                if (rule == null) continue;

                ICriterion innerCriterion = rule.ToCriterion();

                if (innerCriterion == null)
                    continue;

                if (criterion == null)
                    criterion = innerCriterion;
                else if (this.Operator == GroupOperator.And)
                    criterion = new NHibernate.Criterion.AndExpression(criterion, innerCriterion);
                else
                    criterion = new NHibernate.Criterion.OrExpression(criterion, innerCriterion);
            }

            return criterion;
        }
    }

    public enum GroupOperator { 
        And = 0,
        Or = 1
    }
}
